#include "downloadthreadmanager.h"
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QFileInfo>
#include <QEventLoop>

DownloadThreadManager::DownloadThreadManager(QObject *parent) :
    QObject(parent)
{
    m_state = DownloadThread::D_Waiting;
    m_file = NULL;
}

qint64 DownloadThreadManager::getFileSize(const QString& url, int tryTimes)
{
    qint64 size = -1;
    while(tryTimes--)
    {
        QNetworkAccessManager manager;
        QEventLoop loop;
        QNetworkReply *reply = manager.head(QNetworkRequest(url));
        if(!reply)
            continue;
        connect(reply, SIGNAL(finished()), &loop, SLOT(quit()));
        loop.exec();
        if(reply->error() != QNetworkReply::NoError)
        {
            continue;
        }
        size = reply->header(QNetworkRequest::ContentLengthHeader).toLongLong();
        reply->deleteLater();
        break;
    }
    return size;
}

bool DownloadThreadManager::downloadFile(const QString &url)
{
    emit stateChanged(tr("D_Waiting"));
    if(m_state == DownloadThread::D_Downloading)
    {
        qDebug()<<"is downloading a file";
        return false;
    }
    if(THREADCOUNT < 1 || THREADCOUNT > 15)
    {
        qDebug()<<"is thread count error";
        return false;
    }
    if( (m_totalSize = getFileSize(url)) == -1)
    {
        return false;
    }

    QFile tmpFile(QUrl(url).fileName());
    if(!tmpFile.open(QFile::WriteOnly))
    {
        tmpFile.close();
    }
    emit updateFileInfo(QUrl(url).fileName(), m_totalSize);

    m_readySize = 0;
    m_file = new QFile(QUrl(url).fileName() + ".download", this);
    if(!m_file->open(QFile::WriteOnly))
    {
        m_file->close();
        delete m_file;
        m_file = NULL;
        qDebug()<<"can not open file : \n" + m_file->errorString();
        return false;
    }
    m_file->resize(m_totalSize);
    m_threads.clear();
    for(int i=0; i<THREADCOUNT; ++i)
    {
        qint64 startPoint = m_totalSize * i / THREADCOUNT;
        qint64 endPoint = m_totalSize * (i + 1) / THREADCOUNT;
        DownloadThread *thread = new DownloadThread(this);
        connect(thread,SIGNAL(finished(int)),SLOT(finishedSlot(int)));
        connect(thread,SIGNAL(progressChange()),SLOT(progressChangeSlot()));
        connect(thread,SIGNAL(errorCode(int, QString)),
                       SLOT(errorSlot(int, QString)));
        thread->startDownload(i + 1, url, m_file, startPoint, endPoint);
        m_threads.append(thread);
    }

    m_state = DownloadThread::D_Downloading;
    emit stateChanged(tr("D_Downloading"));
    m_runningCount = THREADCOUNT;
    return true;
}

//bool DownloadThreadManager::downloadFile(QString iniFile)
//{
//    if(state == D_Downloading)
//    {
//        errorInfo = "is downloading a file";
//        emit error(0,errorInfo);
//        return false;
//    }
//    if(file != NULL)
//    {
//        errorInfo = "unknow error";
//        emit error(0,errorInfo);
//        return false;
//    }
//    QSettings settings(iniFile,QSettings::IniFormat);

//    url = settings.value("URL").toString();
//    saveFile = settings.value("SAVEFILE").toString();
//    count = settings.value("COUNT",-1).toInt();

//    if(count < 1)
//    {
//        errorInfo = "wrong setting file";
//        emit error(0,errorInfo);
//        return false;
//    }
//    if(count > 15)
//    {
//        errorInfo = "wrong setting file";
//        emit error(0,errorInfo);
//        return false;
//    }

//    totalSize = settings.value("TOTALSIZE",-1).toLongLong();
//    if(totalSize == -1)
//    {
//        return false;
//    }
//    readySize = settings.value("READYSIZE").toLongLong();

//    file = new QFile(saveFile,this);
//    if(!file->open(QFile::WriteOnly | QFile::Append))
//    {
//        errorInfo = "can not open file : \n" + file->errorString();
//        file->close();
//        file = NULL;
//        emit error(0,errorInfo);
//        return false;
//    }
//    file->resize(totalSize);

//    QVector<qint64> infos;
//    for(int i = 0;i < count;i ++)
//    {
//        QString index = QString::number(i + 1);
//        qint64 startPoint = settings.value("STARTPOINT" + index,-1).toLongLong();
//        qint64 endPoint = settings.value("ENDPOINT" + index,-1).toLongLong();
//        qint64 readySize = settings.value("READYSIZE" + index,-1).toLongLong();

//        if(startPoint == -1 || endPoint == -1 || readySize == -1)
//        {
//            errorInfo = "wrong setting file";
//            emit error(0,errorInfo);
//            return false;
//        }
//        infos.append(startPoint);
//        infos.append(endPoint);
//        infos.append(readySize);
//    }

//    threads.clear();
//    for(int i = 0;i < count;i ++)
//    {
//        qint64 startPoint = infos.at(i*3);
//        qint64 endPoint = infos.at(i*3+1);
//        qint64 readySize = infos.at(i*3+2);
//        DownloadThread *thread = new DownloadThread(this);
//        connect(thread,SIGNAL(finished(int)),SLOT(finishedSlot(int)));
//        connect(thread,SIGNAL(progressChange(int,qint64,qint64,qint64)),SLOT(progressChangeSlot(int,qint64,qint64,qint64)));
//        connect(thread,SIGNAL(error(int,QString)),SLOT(errorSlot(int,QString)));
//        thread->startDownload(i + 1,url,file,startPoint,endPoint,readySize);
//        threads.append(thread);
//    }
//    state = D_Downloading;
//    runningCount = count;
//    return true;
//}

void DownloadThreadManager::downloadingFinish()
{
    QString fileName = m_file->fileName();
    m_file->flush();
    m_file->close();
    delete m_file;
    m_file = NULL;
    m_state = DownloadThread::D_Finished;
    foreach(DownloadThread *thread, m_threads)
        thread->deleteLater();
    m_threads.clear();

    QFile::remove(fileName.left(fileName.length() - 9));
    QFile::rename(fileName,fileName.left(fileName.length() - 9));

    emit stateChanged(tr("D_Finished"));
    emit downloadingFinished();
}

void DownloadThreadManager::pause()
{
    if(m_state != DownloadThread::D_Downloading)
    {
        qDebug()<<"is not downloading";
        return;
    }
    m_state = DownloadThread::D_Pause;
    emit stateChanged(tr("D_Pause"));
    foreach(DownloadThread *thread, m_threads)
        thread->stop();
}

void DownloadThreadManager::restart()
{
    if(m_state != DownloadThread::D_Pause)
    {
        qDebug()<<"is not paused";
        return;
    }
    m_state = DownloadThread::D_Downloading;
    emit stateChanged(tr("D_Downloading"));
    foreach(DownloadThread *thread, m_threads)
        thread->restart();
}

void DownloadThreadManager::finishedSlot(int index)
{
    m_runningCount --;
    if(m_runningCount == 0 && m_state == DownloadThread::D_Downloading)
        downloadingFinish();
    qDebug()<<index <<"finished";
}

void DownloadThreadManager::progressChangeSlot()
{
    m_readySize = 0;
    foreach(DownloadThread *thread, m_threads)
        m_readySize += thread->getReadySize();

    emit progressChange(m_readySize , m_totalSize);
}

void DownloadThreadManager::errorSlot(int index, QString errorString)
{
    m_threads.at(index - 1)->stop();
    qDebug()<<index<<errorString;
}
